package cn.juque.jdfsystem.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.juque.common.base.BaseRequestVO;
import cn.juque.common.base.BaseResponseVO;
import cn.juque.common.base.PageInfo;
import cn.juque.common.constants.MessageEnum;
import cn.juque.common.constants.StringConstants;
import cn.juque.common.constants.YesOrNoEnum;
import cn.juque.jdfsystem.cache.FileInfoCache;
import cn.juque.jdfsystem.cache.TpsCache;
import cn.juque.jdfsystem.domain.FileInfoDO;
import cn.juque.jdfsystem.entity.FileInfo;
import cn.juque.jdfsystem.helper.FileInfoHelper;
import cn.juque.jdfsystem.service.IFileInfoService;
import cn.juque.jdfsystem.vo.fileinfo.FileInfoDetailVO;
import cn.juque.jdfsystem.vo.fileinfo.FileInfoListVO;
import cn.juque.jdfsystem.vo.fileinfo.FileInfoSearchVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @author juque
 * @version 1.0.0
 * <ul>
 *     <li>FileInfoController</li>
 * </ul>
 * @date 2023-01-09 11:07:04
 **/
@Slf4j
@Controller
@RequestMapping("/jdf/file")
public class FileInfoController extends BaseController {

    @Resource
    private IFileInfoService fileInfoService;

    @Resource
    private FileInfoHelper fileInfoHelper;

    @Resource
    private FileInfoCache fileInfoCache;

    @Resource
    private TpsCache tpsCache;

    /**
     * 查询
     *
     * @param request BaseRequestVO
     * @return BaseResponseVO
     */
    @PostMapping(value = "/list")
    @ResponseBody
    public BaseResponseVO<List<FileInfoListVO>> list(@RequestBody BaseRequestVO<FileInfoSearchVO> request) {
        FileInfoSearchVO searchVO = super.validatorUtil.checkNotNull(request);
        PageInfo pageInfo = request.getPageInfo();
        super.validatorUtil.checkPageInfo(pageInfo);
        FileInfoDO fileInfo = new FileInfoDO();
        BeanUtil.copyProperties(searchVO, fileInfo);
        List<FileInfoDO> list = this.fileInfoService.listInfoWithPage(pageInfo, fileInfo);
        List<FileInfoListVO> voList = BeanUtil.copyToList(list, FileInfoListVO.class);
        return new BaseResponseVO<>(MessageEnum.OK, voList, pageInfo);
    }

    /**
     * 查询
     *
     * @param id 主键
     * @return BaseResponseVO
     */
    @GetMapping(value = "/detail")
    @ResponseBody
    public BaseResponseVO<FileInfoDetailVO> detail(String id) {
        Assert.notEmpty(id);
        FileInfo fileInfo = this.fileInfoService.detail(id);
        FileInfoDetailVO detailVO = new FileInfoDetailVO();
        BeanUtil.copyProperties(fileInfo, detailVO);
        return new BaseResponseVO<>(MessageEnum.OK, detailVO);
    }

    /**
     * 变更文件状态
     *
     * @param id 主键
     * @return BaseResponseVO
     */
    @GetMapping(value = "/trust")
    @ResponseBody
    public BaseResponseVO<Boolean> trustFile(String id, Boolean flag) {
        Assert.notEmpty(id);
        if(Boolean.TRUE.equals(flag)) {
            this.fileInfoService.trustFile(CollUtil.newArrayList(id), null);
        } else {
            this.fileInfoService.trustFile(null, CollUtil.newArrayList(id));
        }
        return new BaseResponseVO<>(MessageEnum.OK, true);
    }

    /**
     * 上传
     *
     * @param file       文件
     * @param platformId 所属平台
     * @return 文件id
     * @throws IOException IOException
     */
    @PostMapping(value = "/upload")
    @ResponseBody
    public BaseResponseVO<String> upload(@RequestParam("file") MultipartFile file, @RequestParam("platformId") String platformId) throws IOException {
        if (ObjectUtil.isNull(file) || CharSequenceUtil.isEmpty(platformId)) {
            return new BaseResponseVO<>(MessageEnum.PARAM_NULL, null);
        }
        this.tpsCache.incrementUpload();
        String fileId = this.fileInfoHelper.saveFileInfo(this.fileInfoService.toFileInfo(file, platformId));
        return new BaseResponseVO<>(MessageEnum.OK, fileId);
    }

    /**
     * 查看图片
     *
     * @param id 主键
     */
    @GetMapping(value = "/view/{id}")
    public void view(@PathVariable String id, Boolean ignore, HttpServletResponse response) {
        if (CharSequenceUtil.isEmpty(id)) {
            response.setStatus(HttpStatus.NOT_FOUND.value());
            return;
        }
        FileInfo fileInfo = this.fileInfoHelper.detail(id);
        if (null == fileInfo || !YesOrNoEnum.YES.getCode().equals(fileInfo.getValidFlag())) {
            response.setStatus(HttpStatus.NOT_FOUND.value());
            return;
        }
        String fileName = fileInfo.getId() + StringConstants.POINT + fileInfo.getFileExt();
        String clientName = fileInfo.getFileName() + StringConstants.POINT + fileInfo.getFileExt();
        File file = FileUtil.file(fileInfo.getServerPath(), fileName);
        // 是否需要忽略浏览量
        if (!Boolean.TRUE.equals(ignore)) {
            // 记录浏览量
            this.fileInfoCache.incrementPageview(fileInfo);
        }
        this.tpsCache.incrementDownload();
        // 返回数据流
        response.reset();
        response.setContentType(ContentType.APPLICATION_OCTET_STREAM.getMimeType());
        response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
        response.setContentLength((int) file.length());
        try (BufferedInputStream bis = new BufferedInputStream(FileUtil.getInputStream(file));
             OutputStream outputStream = response.getOutputStream()) {
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(clientName, "UTF-8"));
            byte[] buff = new byte[1024];
            int i;
            while ((i = bis.read(buff)) != -1) {
                outputStream.write(buff, 0, i);
                outputStream.flush();
            }
        } catch (Exception e) {
            log.error("file output by stream error", e);
        }
    }

    /**
     * 获取文件的详情
     *
     * @param request BaseRequestVO
     * @return BaseResponseVO
     */
    @PostMapping(value = "/listFileInfo")
    @ResponseBody
    public BaseResponseVO<List<FileInfoDetailVO>> listFileInfo(@RequestBody BaseRequestVO<List<String>> request) {
        this.validatorUtil.checkNotNull(request);
        List<FileInfo> list = this.fileInfoService.detailFileByIds(request.getParam());
        CopyOptions copyOptions = CopyOptions.create(FileInfoDetailVO.class, true,
                "platformId","serverPath", "contentType","validFlag");
        List<FileInfoDetailVO> voList = BeanUtil.copyToList(list, FileInfoDetailVO.class, copyOptions);
        return new BaseResponseVO<>(MessageEnum.OK, voList);
    }
}
